/*
the file extend name should be .aif .
one line can have only one valid command or nothing.
# means in this line,all string after is comments.
{ means sub body start.
} means sub body end.
exe line should be format as " command: format : parameter ", list example:
    wait: time : 2 ; means wait 200ms here,the value is count of 100ms.
    wait: read : please input your command ; means wait until read string " please input your command".
    write: str : change some thing ; means input string "change some thing" .
    write: hex : abc23 ; means input hex 0xab 0xc2 0x03.
    write: file : D:\QtProject?\test.data ; meas input the file data of D:\QtProject?\test.data .
<loop:           count> means loop the following sub body count times, if count == 0 means loop forever.
@include "test.aif" means exe another file test.aif here. this format is reserved for future use.
*/

#include "autointerfile.h"
// #include <QTextIStream>
#include <QTextStream>


cmdList::cmdList()
{
	head  = NULL;
    	next  = NULL;
	node.type = INVALID_TYPE;
}

cmdList::~cmdList()
{
    	delete next;
	if(node.type == LOOP_SUB_CMD)
	{
		delete node.data.LoopData.sublist;
	}
        else if((node.type == AUTO_INTER_CMD)&&
                ((node.data.CmdData.type != INVALID_CMD)&&
                 (node.data.CmdData.type != WAIT_TIME)&&
                 (node.data.CmdData.type != WAIT_WRITE_GAP)))
        {
            delete node.data.CmdData.param.str;
        }
}

bool cmdList::CheckValid()
{
	if(node.type == INVALID_TYPE)
		return false;
	else if(node.type == LOOP_SUB_CMD)
	{
		if( (node.data.LoopData.count < 1)||( node.data.LoopData.sublist == NULL))
			return false;
		else
		{
			if(next)
                                return (next->CheckValid() && (node.data.LoopData.sublist->CheckValid()));
			else
                                return (node.data.LoopData.sublist->CheckValid());
		}
	}
	else
	{
		if(next)
			return next->CheckValid();
		else
			return true;
	}

	return true;
}

cmdList * cmdList::GetRoot()
{
	cmdList * rt = this;
	while(rt->head)
		rt = rt->head;

	return rt;
}

cmdList * cmdList::GetFirstExeCmd()
{
        cmdList * rt = this;
        if(rt->node.type == LOOP_SUB_CMD)
            rt = GetNext();


        return rt;
}

/*
	note that : current can only be auto inter cmd.
	assert( this list is valid);
*/

cmdList * cmdList::GetNext()
{
	cmdList * ret = NULL;
	 if(node.type == LOOP_SUB_CMD)// this condition should not in as current node should only be AUTO_INTER_CMD
	{
		node.data.LoopData.index = node.data.LoopData.count;
		ret = node.data.LoopData.sublist;			
		while(ret->node.type == LOOP_SUB_CMD)
		{
			ret->node.data.LoopData.index = ret->node.data.LoopData.count;
			ret = ret->node.data.LoopData.sublist;
		}
	}
	else if(node.type == AUTO_INTER_CMD)
	{
		if(next)
		{
			ret =  next;
			while(ret->node.type == LOOP_SUB_CMD)
			{
				ret->node.data.LoopData.index = ret->node.data.LoopData.count;
				ret = ret->node.data.LoopData.sublist;
			}
		}
		else// hui suo
		{
			ret = head;
			while( ret && (ret->node.type == LOOP_SUB_CMD))
			{
				if((ret->node.data.LoopData.index > 1)||(ret->next))
					break;
				ret = ret->head;
			}
		
			if((!ret ) || (ret->node.type != LOOP_SUB_CMD))
			{
				ret = NULL; //finished.
			}
			else if (ret->node.data.LoopData.index>1)
			{
				ret->node.data.LoopData.count--;
				ret = ret->node.data.LoopData.sublist;
				while(ret->node.type == LOOP_SUB_CMD)
				{
					ret->node.data.LoopData.index = ret->node.data.LoopData.count;
					ret = ret->node.data.LoopData.sublist;
				}
			}
			else// has next
			{
				ret =  ret->next;
				while(ret->node.type == LOOP_SUB_CMD)
				{
					ret->node.data.LoopData.index = ret->node.data.LoopData.count;
					ret = ret->node.data.LoopData.sublist;
				}
			}
		}
		
	}
	return ret;
}
		


	
autointerfile::autointerfile()
{

}

autointerfile::~autointerfile()
{

}


cmdList * autointerfile::BuildCmdListFromFile(QString fileName)
{
	cmdList * pList = NULL;
    if (isOpen())
    {
       close();
    }
    setFileName(fileName);

    if (! open(QIODevice::ReadOnly))
    {
         m_errorinfo = tr("Could not open aif file %1 for reading.").arg(fileName);
         return NULL;
    }
    if(false == checkValid())
    {
        m_errorinfo = tr("Aif file %1 is not valid.").arg(fileName);
        return NULL;
    }
    /*			*/
        seek(0);
    pList = buildSubCmdList(NULL);

    close();
    return pList;
}

bool autointerfile::checkValid()
{

    return true;
}

 cmdList * autointerfile::buildSubCmdList(cmdList * pHead)
{
    bool SubStart = false;
    cmdList * pCur = NULL,* pLast = NULL, * pFirst = NULL;
    int il, ir, ifm, ism;
    QTextStream stm( this);
    QString tmp ,source ,part1, part2,part3;
    int pos;

    tmp = stm.readLine();
    while(! tmp.isNull())
    {
        source = tmp;
        if(-1 !=(pos = tmp.indexOf('#')))
            tmp = tmp.left(pos);
        if(tmp.trimmed() == "{")
            SubStart = true;
        if(SubStart)
        {
                if(tmp.trimmed() == "}")
                     break;
	        tmp = tmp.trimmed();
	        il = tmp.indexOf('<');
	        ir = tmp.indexOf('>');
	        ifm = tmp.indexOf(':');
	        ism = tmp.indexOf(':',ifm+1);
                if((il!= -1)&& (ir>ifm) &&(ifm >il))
	        {
	            part1 = tmp.mid(il+1,ifm-il-1);
	            part2 = tmp.mid(ifm+1,ir-ifm-1);
	            if(part1.trimmed() == "loop")
	            {
	                pCur = new cmdList;
	                pCur->head = pHead;
	                pCur->node.type = LOOP_SUB_CMD;
	                pCur->node.data.LoopData.count = part2.toInt();
	                pCur->SourceString = source;
	                pCur->node.data.LoopData.sublist = buildSubCmdList(pCur);
	            }
	        }
	        else if((ifm != -1)&&(ism > ifm))
	        {
	            part1 = tmp.left(ifm);
	            part2 = tmp.mid(ifm+1,ism-ifm-1);
	            part3 = tmp.right(tmp.length() - ism -1);
	            if(part1.trimmed() == "wait")
	            {
	                if(part2.trimmed() == "time")
	                {
	                    pCur = new cmdList;
	                    pCur->head = pHead;
	                    pCur->node.type = AUTO_INTER_CMD;
	                    pCur->node.data.CmdData.type = WAIT_TIME;
	                    pCur->node.data.CmdData.param.count = part3.toInt();
	                    pCur->SourceString = source;
	                }
	                else if(part2.trimmed() == "read")
	                {
	                    pCur = new cmdList;
	                    pCur->head = pHead;
	                    pCur->node.type = AUTO_INTER_CMD;
	                    pCur->node.data.CmdData.type = WAIT_READ;
                            pCur->node.data.CmdData.param.str = new QString (part3.trimmed());
	                    pCur->SourceString = source;
	                }
	            }
	            else if(part1.trimmed() == "write")
	            {
	                if(part2.trimmed() == "str")
	                {
	                    pCur = new cmdList;
	                    pCur->head = pHead;
	                    pCur->node.type = AUTO_INTER_CMD;
	                    pCur->node.data.CmdData.type = WRITE_STR;
                            pCur->node.data.CmdData.param.str = new QString(part3.trimmed() + m_endFix);
	                    pCur->SourceString = source;
	                }
	                else if(part2.trimmed() == "hex")
	                {
	                    pCur = new cmdList;
	                    pCur->head = pHead;
	                    pCur->node.type = AUTO_INTER_CMD;
	                    pCur->node.data.CmdData.type = WRITE_HEX;
                            pCur->node.data.CmdData.param.str =  new QString(part3.trimmed());
	                    pCur->SourceString = source;
	                }
	                else if(part2.trimmed() == "file")
	                {
	                    pCur = new cmdList;
	                    pCur->head = pHead;
	                    pCur->node.type = AUTO_INTER_CMD;
	                    pCur->node.data.CmdData.type = WRITE_FILE;
                            pCur->node.data.CmdData.param.str =  new QString(part3.trimmed());
	                    pCur->SourceString = source;

	                }
	            }
	        }
			   if(pCur)
			   	{
				   	if(pLast)
	                    			pLast->next = pCur;
	                		pLast = pCur;
					pCur = NULL;
					if(NULL == pFirst)
						pFirst = pLast;
			   	}
        }
        tmp = stm.readLine();
    }
    return pFirst;
}

